#include <speex/speex.h>
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <pthread.h>

#include "sampledec.h"

#define ALSA_PCM_NEW_HW_PARAMS_API

snd_pcm_t *handle; 		
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem_decode;
char **argvapp;

int idargv[MAX_DECODE_THREAD_COUNT];

PCMBuffer pcmBuffer[MAX_DECODE_THREAD_COUNT][BUFFER_COUNT];
pPCMBuffer getLinkHeader[MAX_DECODE_THREAD_COUNT];// = &pcmBuffer[0];//定义读指针
pPCMBuffer putLinkHeader[MAX_DECODE_THREAD_COUNT];// = &pcmBuffer[0];//定义写指针
int validBufferCount[MAX_DECODE_THREAD_COUNT];//=0;//缓冲区个数
/*
PCMBuffer pcmBuffer_2[BUFFER_COUNT];
pPCMBuffer getLinkHeader_2 = &pcmBuffer_2[0];//定义读指针
pPCMBuffer putLinkHeader_2 = &pcmBuffer_2[0];//定义写指针
int validBufferCount_2=0;//缓冲区个数

PCMBuffer pcmBuffer_3[BUFFER_COUNT];
pPCMBuffer getLinkHeader_3 = &pcmBuffer_3[0];//定义读指针
pPCMBuffer putLinkHeader_3 = &pcmBuffer_3[0];//定义写指针
int validBufferCount_3=0;//缓冲区个数
*/

/****************************************************************************************
*   函数名: init_alsa_play
*   输  入: 无
*   输  出: 无
*   功能说明：alsa音频播放器初始化
*
*       
******************************************************************************************/
void init_alsa_play()
{
	int rc; 
	int size; 		
	snd_pcm_uframes_t frames; 
	int channels = 2;//立体声
	int rate=44100;//采样率
	char *buffer; 
	snd_pcm_hw_params_t *params; 
	unsigned int val; 
	int dir; 
				
		/* Open PCM device for playback. */
		rc=snd_pcm_open(&handle,"default", SND_PCM_STREAM_PLAYBACK, 0);
		if (rc< 0) 
		{ 
			fprintf(stderr,  "unable to open pcm device: %s\n",    snd_strerror(rc));
			exit(1); 
		} 
		 
		/* Allocate a hardware parameters object. */
		 snd_pcm_hw_params_alloca(&params); 
		/* Fill it in with default values. */
		 snd_pcm_hw_params_any(handle, params);
		 /* Set the desired hardware parameters. */ 

		/* Interleaved mode */ 
		snd_pcm_hw_params_set_access(handle,params, SND_PCM_ACCESS_RW_INTERLEAVED); 

		/* Signed 16-bit little-endian format 格式*/ 
		snd_pcm_hw_params_set_format(handle,params, SND_PCM_FORMAT_S16_LE); 


		/* Two channels (stereo) 声道*/  
		snd_pcm_hw_params_set_channels(handle, params, channels); 
		/* 44100 bits/second sampling rate (CD quality) 采样率设置*/ 
		snd_pcm_hw_params_set_rate_near(handle,params, &rate, &dir);  /* Set period size to 32 frames. */ 
		frames = 80; 
		snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
		/* Write the parameters to the driver */
		 rc = snd_pcm_hw_params(handle, params);
		 if (rc < 0) 
		 {   
				fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));   
				exit(1); 
		}

		/*Use a buffer large enough to hold one period*/
		snd_pcm_hw_params_get_period_size(params, &frames,  &dir); //32个采样点算一帧
		size = frames * (channels);
		/* 2 bytes/sample, 2 channels */ 
		buffer = (char *) malloc(size); 
		/* We want to loop for 5 seconds */
		snd_pcm_hw_params_get_period_time(params, &val, &dir); 
}


int speex_play_thread_func()
{
	short tmp[FRAME_SIZE];
	int i, j;
		
	while(1)
	{
		sem_wait(&sem_decode);
		memset(&tmp[0], 0, sizeof(tmp));
			
		for(j=0;j<MAX_DECODE_THREAD_COUNT;j++)
		{
			if(validBufferCount[j]>1)
			{
				for(i=0;i<FRAME_SIZE;i++)
				{
					tmp[i] += getLinkHeader[j]->out[i];
				}

				getLinkHeader[j] = getLinkHeader[j]->next;
				//getLinkHeader_2 = getLinkHeader_2->next;
				//getLinkHeader_3 = getLinkHeader_3->next;			
				validBufferCount[j]--;
				//validBufferCount_2--;
				//validBufferCount_3--;			
		    	printf("validBufferCount[%d]=%d\n", j, validBufferCount[j]);
			}
		}
		
    	snd_pcm_writei(handle, tmp, 80); 		
	}
}

int speex_decode_file_thread_func(int* tid)
{
   FILE *fin[1];
   /*Holds the audio that will be written to file (16 bits per sample)*/
   //short out[FRAME_SIZE];
   /*Speex handle samples as float, so we need an array of floats*/
   float output[FRAME_SIZE];
   char cbits[200];
   int nbBytes;
   /*Holds the state of the decoder*/
   void *state;
   /*Holds bits so they can be read and written to by the Speex routines*/
   SpeexBits bits;
   int i, tmp;
    char filename[100];
    memcpy(&filename[0], argvapp[(*tid)+1], strlen(argvapp[(*tid)+1]));
    
	printf("%s: filename = %s, *tid=%d\n", __func__, (char*)filename, *tid);
	
   /*Create a new decoder state in narrowband mode*/
   state = speex_decoder_init(&speex_nb_mode);

   /*Set the perceptual enhancement on*/
   tmp=1;
   speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
   //printf("%s: 22222222\n", __func__);
	 //inFile[0]	= argv[1];
	 //inFile[1]	= argv[2];	 
//   outFile = argv[1];
   //fout = fopen(outFile, "w");
   fin[0] = fopen(filename, "r");//打开输入的spx文件
   
   if(fin[0] ==NULL)
   {
     perror("打开文件错误");
     return;
     //exit(1);
   }
   
   //printf("%s: 3333333\n", __func__);
   /*Initialization of the structure that holds the bits*/
   speex_bits_init(&bits);
   //printf("%s: 4444444\n", __func__);   
   while (1)
   {   //printf("%s: 55555\n", __func__);
      //printf("%s: 1111111\n", __func__);
      /*Read the size encoded by sampleenc, this part will likely be 
        different in your application*/
      fread(&nbBytes, sizeof(int), 1, fin[0]);
      //fprintf (stderr, "nbBytes: %d\n", nbBytes);
      if (feof(fin[0]))
         break;
         //printf("%s: 666\n", __func__);
      /*Read the "packet" encoded by sampleenc*/
      fread(cbits, 1, nbBytes, fin[0]);
      /*Copy the data into the bit-stream struct*/
      speex_bits_read_from(&bits, cbits, nbBytes);
         //printf("%s: 777\n", __func__);
      /*Decode the data*/
      speex_decode(state, &bits, output);
   //printf("%s: 88888\n", __func__);
   //printf("%s: 88888\n", __func__);
   //printf("%s: 88888\n", __func__);
   //printf("%s: 88888\n", __func__);
   //printf("%s: 88888\n", __func__);
   //printf("%s: 88888\n", __func__);               
   //printf("%s: 99999999\n", __func__);               
   			//printf("aaaaa\n");   			
   			//printf("bbbbbbb\n");
   //printf("%s: 99999999\n", __func__);               
   //printf("%s: 99999999\n", __func__);               
   			//printf("cccccccccccccccccccc\n");
   //printf("%s: 99999999\n", __func__);               
   			//printf("dddddddddddddd\n");
   //printf("%s: 99999999\n", __func__);               
   			//printf("eeeeeeeeeeeeeeeeeeeeeeeeeeeee\n");   			   			   			   			
      /*Copy from float to short (16 bits) for output*/
      for (i=0;i<FRAME_SIZE;i++)
      {
         //out[i]=output[i];
			putLinkHeader[*tid]->out[i] = output[i];
			//printf("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n");
			//printf("putLinkHeader[*tid]->out[i]=%d\n", putLinkHeader[0]->a);
		}
   //printf("%s: 999999xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", __func__);
      /*Write the decoded audio to file*/
      //fwrite(out, sizeof(short), FRAME_SIZE, fout);
      //pthread_mutex_lock(&mutex);
      //snd_pcm_writei(handle, out, 80); 
        putLinkHeader[*tid] = putLinkHeader[*tid]->next;//写指针指向下一个节点
        //pthread_mutex_unlock(&mutex);
	validBufferCount[*tid]++;
        printf("d%d\n", validBufferCount[*tid]);
		sem_post(&sem_decode);
	if(validBufferCount[*tid] > 100)
	usleep(2000);
         //printf("%s: ddddddddd\n", __func__);
   }
   
   /*Destroy the decoder state*/
   speex_decoder_destroy(state);
   /*Destroy the bit-stream truct*/
   speex_bits_destroy(&bits);
   fclose(fin[0]);	
}

#if 0
int speex_decode_file_thread2_func(void* filename)
{
   FILE *fin[1];
   /*Holds the audio that will be written to file (16 bits per sample)*/
   //short out[FRAME_SIZE];
   /*Speex handle samples as float, so we need an array of floats*/
   float output[FRAME_SIZE];
   char cbits[200];
   int nbBytes;
   /*Holds the state of the decoder*/
   void *state;
   /*Holds bits so they can be read and written to by the Speex routines*/
   SpeexBits bits;
   int i, tmp;
      
	printf("%s: filename = %s\n", __func__, (char*)filename);
	
   /*Create a new decoder state in narrowband mode*/
   state = speex_decoder_init(&speex_nb_mode);

   /*Set the perceptual enhancement on*/
   tmp=1;
   speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
   //printf("%s: 22222222\n", __func__);
	 //inFile[0]	= argv[1];
	 //inFile[1]	= argv[2];	 
//   outFile = argv[1];
   //fout = fopen(outFile, "w");
   fin[0] = fopen(filename, "r");//打开输入的spx文件
   
   if(fin[0] ==NULL)
   {
     perror("打开文件错误");
     return;
     //exit(1);
   }
   
   //printf("%s: 3333333\n", __func__);
   /*Initialization of the structure that holds the bits*/
   speex_bits_init(&bits);
   //printf("%s: 4444444\n", __func__);   
   while (1)
   {   //printf("%s: 55555\n", __func__);
      //printf("%s: 1111111\n", __func__);
      /*Read the size encoded by sampleenc, this part will likely be 
        different in your application*/
      fread(&nbBytes, sizeof(int), 1, fin[0]);
      //fprintf (stderr, "nbBytes: %d\n", nbBytes);
      if (feof(fin[0]))
         break;
         //printf("%s: 666\n", __func__);
      /*Read the "packet" encoded by sampleenc*/
      fread(cbits, 1, nbBytes, fin[0]);
      /*Copy the data into the bit-stream struct*/
      speex_bits_read_from(&bits, cbits, nbBytes);

      /*Decode the data*/
      speex_decode(state, &bits, output);

      /*Copy from float to short (16 bits) for output*/
      for (i=0;i<FRAME_SIZE;i++)
         //out[i]=output[i];
	putLinkHeader_2->out[i] = output[i];
   //printf("%s: 88888\n", __func__);
      /*Write the decoded audio to file*/
      //fwrite(out, sizeof(short), FRAME_SIZE, fout);
      //pthread_mutex_lock(&mutex);
      //snd_pcm_writei(handle, out, 80); 
        putLinkHeader_2 = putLinkHeader_2->next;//写指针指向下一个节点
        //pthread_mutex_unlock(&mutex);
	validBufferCount_2++;
        printf("d%d\n", validBufferCount_2);
		sem_post(&sem_decode);
	if(validBufferCount_2 > 100)
	usleep(2000);
         //printf("%s: 99999\n", __func__);
   }
   
   /*Destroy the decoder state*/
   speex_decoder_destroy(state);
   /*Destroy the bit-stream truct*/
   speex_bits_destroy(&bits);
   fclose(fin[0]);	
}

int speex_decode_file_thread3_func(void* filename)
{
   FILE *fin[1];
   /*Holds the audio that will be written to file (16 bits per sample)*/
   //short out[FRAME_SIZE];
   /*Speex handle samples as float, so we need an array of floats*/
   float output[FRAME_SIZE];
   char cbits[200];
   int nbBytes;
   /*Holds the state of the decoder*/
   void *state;
   /*Holds bits so they can be read and written to by the Speex routines*/
   SpeexBits bits;
   int i, tmp;
      
	printf("%s: filename = %s\n", __func__, (char*)filename);
	
   /*Create a new decoder state in narrowband mode*/
   state = speex_decoder_init(&speex_nb_mode);

   /*Set the perceptual enhancement on*/
   tmp=1;
   speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
   //printf("%s: 22222222\n", __func__);
	 //inFile[0]	= argv[1];
	 //inFile[1]	= argv[2];	 
//   outFile = argv[1];
   //fout = fopen(outFile, "w");
   fin[0] = fopen(filename, "r");//打开输入的spx文件
   
   if(fin[0] ==NULL)
   {
     perror("打开文件错误");
     return;
     //exit(1);
   }
   
   //printf("%s: 3333333\n", __func__);
   /*Initialization of the structure that holds the bits*/
   speex_bits_init(&bits);
   //printf("%s: 4444444\n", __func__);   
   while (1)
   {   //printf("%s: 55555\n", __func__);
      //printf("%s: 1111111\n", __func__);
      /*Read the size encoded by sampleenc, this part will likely be 
        different in your application*/
      fread(&nbBytes, sizeof(int), 1, fin[0]);
      //fprintf (stderr, "nbBytes: %d\n", nbBytes);
      if (feof(fin[0]))
         break;
         //printf("%s: 666\n", __func__);
      /*Read the "packet" encoded by sampleenc*/
      fread(cbits, 1, nbBytes, fin[0]);
      /*Copy the data into the bit-stream struct*/
      speex_bits_read_from(&bits, cbits, nbBytes);

      /*Decode the data*/
      speex_decode(state, &bits, output);

      /*Copy from float to short (16 bits) for output*/
      for (i=0;i<FRAME_SIZE;i++)
         //out[i]=output[i];
	putLinkHeader_3->out[i] = output[i];
   //printf("%s: 88888\n", __func__);
      /*Write the decoded audio to file*/
      //fwrite(out, sizeof(short), FRAME_SIZE, fout);
      //pthread_mutex_lock(&mutex);
      //snd_pcm_writei(handle, out, 80); 
        putLinkHeader_3 = putLinkHeader_3->next;//写指针指向下一个节点
        //pthread_mutex_unlock(&mutex);
	validBufferCount_3++;
        printf("d%d\n", validBufferCount_3);
		sem_post(&sem_decode);
	if(validBufferCount_3 > 100)
	usleep(2000);
         //printf("%s: 99999\n", __func__);
   }
   
   /*Destroy the decoder state*/
   speex_decoder_destroy(state);
   /*Destroy the bit-stream truct*/
   speex_bits_destroy(&bits);
   fclose(fin[0]);	
}
#endif

int main(int argc, char **argv)
{
   char *outFile;
   char *inFile[1];
// FILE *fout;
	int i, j;
   int err;

   pthread_t tid_speex_decode_file[MAX_DECODE_THREAD_COUNT];
   //pthread_t tid_speex_decode_file_2;   
   //pthread_t tid_speex_decode_file_3;      
   pthread_t tid_speex_alsa_play;   
   
   printf("%s: start 111\n", __func__);
   
   argvapp = argv;
   
	 init_alsa_play();
	
	err = sem_init(&sem_decode, 0, 0);
	if (err != 0)
	{
		perror("Semaphore initialization failed");
	}

	for(j=0;j<MAX_DECODE_THREAD_COUNT;j++)
	{
		//初始化环形缓冲区
		for(i=0;i<BUFFER_COUNT;i++)
		{
			memset(&pcmBuffer[j][i].out[0], 0, FRAME_SIZE);
			pcmBuffer[j][i].next = &pcmBuffer[j][i+1];
		}
		pcmBuffer[j][BUFFER_COUNT-1].next =  &pcmBuffer[j][0];
		
		putLinkHeader[j] = &pcmBuffer[j][0];
		getLinkHeader[j] = &pcmBuffer[j][0];		
	}
/*
	//初始化环形缓冲区
	for(i=0;i<BUFFER_COUNT;i++)
	{
		memset(&pcmBuffer_2[i].out[0], 0, FRAME_SIZE);
		pcmBuffer_2[i].next = &pcmBuffer_2[i+1];
	}
	pcmBuffer_2[BUFFER_COUNT-1].next =  &pcmBuffer_2[0];

	//初始化环形缓冲区
	for(i=0;i<BUFFER_COUNT;i++)
	{
		memset(&pcmBuffer_3[i].out[0], 0, FRAME_SIZE);
		pcmBuffer_3[i].next = &pcmBuffer_3[i+1];
	}
	pcmBuffer_3[BUFFER_COUNT-1].next =  &pcmBuffer_3[0];
*/	

	for(i=0;i<MAX_DECODE_THREAD_COUNT;i++)
	{
	 idargv[i] = i;
	 err = pthread_create(&tid_speex_decode_file[i], NULL, (void*)speex_decode_file_thread_func, &idargv[i]/*argv[i+1]*/);	 
	 if(err != 0)
	 {
	 		perror("创建解码线程错误");
	 }
	 usleep(1000);
	}
/*
	 err = pthread_create(&tid_speex_decode_file_2, NULL, (void*)speex_decode_file_thread2_func, argv[2]);	 
	 if(err != 0)
	 {
	 		perror("创建解码线程2错误");
	 }

	 err = pthread_create(&tid_speex_decode_file_3, NULL, (void*)speex_decode_file_thread3_func, argv[3]);
	 if(err != 0)
	 {
	 		perror("创建解码线程3错误");
	 }
*/	 
	 err = pthread_create(&tid_speex_alsa_play, NULL, (void*)speex_play_thread_func, argv[2]);
	 
	 if(err != 0)
	 {
	 		perror("创建播放线程错误");
	 }
	 	 
	for(i=0;i<MAX_DECODE_THREAD_COUNT;i++)
	{	 	 
	   pthread_join(tid_speex_decode_file[i], NULL);
   	}
   /*
   pthread_join(tid_speex_decode_file_2, NULL);
   pthread_join(tid_speex_decode_file_3, NULL);   
   */
   pthread_join(tid_speex_alsa_play, NULL);
   return 0;
}
